package maskedpixel
{
	import net.flashpunk.FP;
	import maskedpixel.enums.AXIS;
	//import flash.geom.Vector2D;
	/**
	 * MpPhysics
	 * 
	 * 
	 * @link http://www.maskedpixelgames.com
	 * @author Erin M Gunn
	 */
	public class MpPhysics
	{
		
		/**
		 * Set the maximum velocity on each axis a MpEntity can move.  Useful when using acceleration.
		 * @param	source		The MpEntity to set the maximum velocity of.
		 * @param	vX			The maximum velocity on the x axis in px/s.
		 * @param	vY			The maximum velocity on the y axis in px/s.
		 */
		public static function setMaxVelocity(source:MpEntity, vX:uint, vY:uint):void
		{
			source.maxVelocity.x = vX;
			source.maxVelocity.y = vY;
		}
		
		/**
		 * Accellerate the target source along a specified axis.  This function is additive and does not replace the value<br>
		 * stored in the source's acceleration variable.
		 * @param	source		MpEntity to apply the acceleration to.
		 * @param	axis		The axis on which to accellerate the source on.
		 * @param	accel		The acceleration to apply on the axis to the source in px/s^2.
		 */
		public static function accellerateOnAxis(source:MpEntity, axis:uint, accel:uint):void
		{
			switch(axis)
			{
				case AXIS.NEGX:
					source.acceleration.x += -accel;
					break;
				case AXIS.POSX:
					source.acceleration.x += accel;
					break;
				case AXIS.NEGY:
					source.acceleration.y += -accel;
					break;
				case AXIS.POSY:
					source.acceleration.y += accel;
					break;
			}
		}
		
		/**
		 * Move the target source along a specified axis.  This function is additive and does not replace the value<br>
		 * stored in the source's velocity variable.
		 * @param	source		MpEntity to move.
		 * @param	axis		The axis on which to move the source on.
		 * @param	speed		The speed to move the source on the specified axis in px/s.
		 */
		public static function moveOnAxis(source:MpEntity, axis:uint, speed:int):void
		{
			switch(axis)
			{
				case AXIS.NEGX:
					source.velocity.x += -speed;
					break;
				case AXIS.POSX:
					source.velocity.x += speed;
					break;
				case AXIS.NEGY:
					source.velocity.y += -speed;
					break;
				case AXIS.POSY:
					source.velocity.y += speed;
					break;
			}
		}
		
		/**
		 * Accelerate the source towards the specified Vector2D at the specified accel.  This function is additive<br>
		 * and does replace the value stored in the sources acceleration variable.
		 * @param	source		The MpEntity on which the acceleration will be added.
		 * @param	target		The Vector2D cordinates to move the source towards.
		 * @param	accel		The acceleration in which to accelerate the source in px/s^2.
		 */
		public static function accelerateTowardsVector2D(source:MpEntity, target:Vector2D, accel:int = 60):void
		{
			var a:Number = angleBetweenVector2D(source, target);
			
			source.acceleration.x = int(Math.cos(a) * accel);
			source.acceleration.y = int(Math.sin(a) * accel);
		}
		
		/**
		 * Accelerate the source on a specified Vector2D at the specified accel.  This function is additive<br>
		 * and does replace the value stored in the sources acceleration variable.
		 * @param	source		The MpEntity on which the acceration will be added.
		 * @param	angle		The Angle in Radians to accelerate the MpEntity at.
		 * @param	accel		The acceleration in which to accelerate the source in px/s^2.
		 */
		public static function accelerateTowardsAngle(source:MpEntity, angle:Number, accel:Number = 60):void
		{
			source.acceleration.x = Math.cos(angle) * accel;
			source.acceleration.y = Math.sin(angle) * accel;
		}
		
		/**
		 * Move the source MpEntity towards the target Vector2D at the specified speed.  This function is additive<br>
		 * and does not replace the value stored in the sources velocity variable.
		 * @param	source		The MpEntity on which the velocity will be added.
		 * @param	target		The Vector2D coordinates to move the source towards.
		 * @param	speed		The speed at which to move the source in px/s.
		 */
		public static function moveTowardsVector2D(source:MpEntity, target:Vector2D, speed:int):void
		{
			var a:Number = angleBetweenVector2D(source, target);
			
			source.velocity.x += int(Math.cos(a) * speed);
			source.velocity.y += int(Math.sin(a) * speed);
		}
		
		/**
		 * Find the angle (in radians) between an MpEntity and an Vector2D. The source sprite takes its x/y and origin into account.
		 * The angle is calculated in clockwise positive direction (down = 90 degrees positive, right = 0 degrees positive, up = 90 degrees negative)
		 * @param	a			The MpEntity to test from
		 * @param	target		The Vector2D to angle the MpEntity towards
		 * @param	asDegrees	If you need the value in degrees instead of radians, set to true
		 * 
		 * @return	Number The angle (in radians unless asDegrees is true)
		 */
		public static function angleBetweenVector2D(a:MpEntity, target:Vector2D, asDegrees:Boolean = false):Number
        {
			var dx:Number = (target.x) - (a.x + a.origin.x);
			var dy:Number = (target.y) - (a.y + a.origin.y);
			
			if (asDegrees)
			{
				return Math.atan2(dy, dx) * FP.DEG;
			}
			else
			{
				return Math.atan2(dy, dx);
			}
        }
		
		/**
		 * Find the angle (in radians) between the origins of the two specified MpEntitys.
		 * @param	a			The MpEntity to test from.
		 * @param	b			The MpEntity to test to.
		 * @param	asDegrees	If you need Degrees instead of Radians, set to true.
		 * @return
		 */
		public static function angleBetweenObjects(a:MpEntity, b:MpEntity, asDegrees:Boolean = false):Number
		{
			var dx:Number = (b.x + b.origin.x) - (a.x + a.origin.x);
			var dy:Number = (b.y + b.origin.y) - (a.y + a.origin.y);
			
			if (asDegrees)
			{
				return Math.atan2(dy, dx) * FP.DEG;
			}
			else
			{
				return Math.atan2(dy, dx);
			}
		}
		
		/**
		 * A tween-like function that takes a starting velocity
		 * and some other factors and returns an altered velocity.
		 * 
		 * @param	Velocity		Any component of velocity (e.g. 20).
		 * @param	Acceleration	Rate at which the velocity is changing.
		 * @param	Drag			Really kind of a deceleration, this is how much the velocity changes if Acceleration is not set.
		 * @param	Max				An absolute value cap for the velocity.
		 * 
		 * @return	The altered Velocity value.
		 */
		public static function computeVelocity(Velocity:Number, Acceleration:Number=0, Drag:Number=0, Max:Number=10000):Number
		{
			if(Acceleration != 0)
				Velocity += Acceleration * FP.elapsed;
			else if(Drag != 0) 
			{
				var drag:Number = Drag * FP.elapsed;
				if(Velocity - drag > 0)
					Velocity = Velocity - drag;
				else if(Velocity + drag < 0)
					Velocity += drag;
				else
					Velocity = 0;
			}
			if((Velocity != 0) && (Max != 10000))
			{
				if(Velocity > Max)
					Velocity = Max;
				else if(Velocity < -Max)
					Velocity = -Max;
			}
			return Velocity;
		}
	}
}